import { _RequstInterceptors } from '@/api/axios/Interceptors'
import type {
  AxiosError,
  AxiosInstance,
  AxiosRequestConfig,
  AxiosResponse,
  InternalAxiosRequestConfig,
} from 'axios'
import axios from 'axios'
import type { AxiosOptions } from '@/api/axios/type'
class Axios {
  #axiosInstance: AxiosInstance
  #options: AxiosOptions
  #interceptors

  constructor(options: any) {
    this.#axiosInstance = axios.create(options)
    this.#options = options
    this.#interceptors = options.interceptors
    this.setInterceptors()
  }

  request<T = unknown>(config: AxiosRequestConfig): Promise<T> {
    return new Promise((resolve, reject) => {
      this.#axiosInstance
        .request<unknown, AxiosResponse<T>>(config)
        .then((res) => {
          return resolve(res as unknown as Promise<T>)
        })
        .catch((err) => {
          return reject(err)
        })
    })
  }

  get<T = unknown>(config: AxiosRequestConfig): Promise<T> {
    return this.request<T>({ ...config, method: 'GET' })
  }

  post<T = unknown>(config: AxiosRequestConfig): Promise<T> {
    return this.request<T>({ ...config, method: 'POST' })
  }

  put<T = unknown>(config: AxiosRequestConfig): Promise<T> {
    return this.request<T>({ ...config, method: 'PUT' })
  }

  delete<T = unknown>(config: AxiosRequestConfig): Promise<T> {
    return this.request<T>({ ...config, method: 'DELETE' })
  }

  setInterceptors() {
    if (!this.#interceptors) return
    const {
      requestInterceptors,
      requestInterceptorsCatch,
      responseInterceptors,
      responseInterceptorsCatch,
    } = this.#interceptors

    this.#axiosInstance.interceptors.request.use((config: InternalAxiosRequestConfig) => {
      if (requestInterceptors) config = requestInterceptors(config)
      return config
    }, requestInterceptorsCatch ?? undefined)

    this.#axiosInstance.interceptors.response.use(
      async (response: AxiosResponse) => {
        if (responseInterceptors) response = await responseInterceptors(response)
        if (this.#options.directlyGetdata && response.data) response = response.data
        return response
      },
      async (err: AxiosError) => {
        if (responseInterceptorsCatch) {
          return await responseInterceptorsCatch(this.#axiosInstance, err)
        }
        return err
      },
    )
  }
}

const Request = new Axios({
  directlyGetdata: true,
  baseURL: '/api',
  timeout: 10 * 1000,
  interceptors: _RequstInterceptors,
  headers: { 'Content-Type': 'application/json' },
  retryConfig: {
    count: 5,
    waitTime: 500,
  },
})

export default Request
